#!/usr/bin/python

import pygame
import Graph
import Vertex
import Algorithm
import utils
import sys
import me as pointer
import pdb
import threading
import Loading
import Messages
import copy
import graph_autogen

str_opciones = "pulsa 'd' para Dijkstra, 'c' para cartero chino,\n'l' para cargar, 'g' para generar grafo"

class loading(threading.Thread):
	def __init__(self,screen):
		self.sound = utils.load_sound("loading1.wav")
		self.sound2 = utils.load_sound("loading2.wav")
		self.font = pygame.font.Font(None, 60)
		self.screen = screen
		self.running = True
		self.loading = "Cargando"
		self.loadimg = Loading.Loading(self.screen)
		threading.Thread.__init__(self)
	def run(self):
		self.sound.play(-1)
		points = 0
		index = 0
		while self.running:
			pygame.time.Clock().tick(40)
			if index % 10 == 0:
				points +=1
				points %= 4
				
				points2 = "   "
				if points == 1:
					points2 = ".  "
				elif points == 2:
					points2 = ".. "
				elif points == 3:
					points2 = "..."
					
			self.text = self.font.render(self.loading+points2, 1, (240,100,0))
			self.screen.fill((255,255,255))
			x,y = self.screen.get_rect().center
			x-= self.text.get_width() / 2
			y += self.loadimg.image.get_height() / 2
			self.screen.blit(self.text, (x,y))
			self.loadimg.update()
			self.screen.blit(self.loadimg.image, self.loadimg.rect)
			
			pygame.display.flip()
			index += 1

		
		self.sound.stop()
		self.sound2.play()
	

def main():
	#initializating pygame
	pygame.init()
	screen = pygame.display.set_mode((1024, 700), pygame.DOUBLEBUF | pygame.RESIZABLE)
	pygame.display.set_caption('Nav')
	
	l = loading(screen)
	l.start()

	scroll_x, scroll_y = 0,0
	
	#this is the font object that we use to paint text
	font = pygame.font.Font(None, 20)
	
	if len(sys.argv) < 2:
		file_to_open = "55.graph"
	else:
		file_to_open = sys.argv[1]
		
	g = Graph.Graph(file_to_open)

	max = [0, 0]
	for v in g.get_vertices():
		if v.get_x() > max[0]:
			max[0] = v.get_x()
		if v.get_y() > max[1]:
			max[1] = v.get_y()
	
	screen_buffer = pygame.Surface((max[0]+50, max[1]+50))
	vertices = g.get_vertices()

	#calculating the vertices position and storing in a vector
	#also the names of vertices
	vertices2 = []
	for vertex in vertices:
		text = font.render(vertex.get_name(), 1, (255,255,255))
		x,y = vertex.get_pos()
		x-= text.get_width()/2
		y-= text.get_height()/2
		#[(vertex-pos, vertex-name, name-pos)]
		vertices2.append((vertex.get_pos(), text, (x,y)))

	#calculating the edges for drawing
	drawed = []
	weights = []
	edges = []
	for vertex in vertices:
		for adjacent in vertex.get_adjacents():
			x,y = vertex.get_pos()
			z,t = adjacent.get_pos()
			#we not include the repeated edges, a-b == b-a
			#we only paint one of these
			if member(drawed, (x,y,z,t)) or member(drawed, (z,t,y,x)):
				continue
			drawed+=[(x,y,z,t)]
			edges.append(((x,y),(z,t)))
			text = font.render(str(g.get_weight(vertex.get_name(),adjacent.get_name())), 1, (0,0,0))
			posx = (x+z) / 2
			posy = (y+t) / 2
			#[(weight, position)]
			weights.append((text,(posx,posy)))

	path = []
	src = "0"
	dst = str(len(g.get_vertices())- 1)
	path = Algorithm.Dijkstra(g, src, dst)
	
	g2 = copy.deepcopy(g)
	cpp_path = Algorithm.CPP(g) # , src, file_to_open)
	print cpp_path
	#calculating the eulerian path
	cpp = []
	vertex1 = g.find_by_name(cpp_path[0])
	for i,vertex in enumerate(cpp_path[1:]):
		vertex = g.find_by_name(cpp_path[i])
		x,y = vertex1.get_pos()
		z,t = vertex.get_pos()
		
		vertex1 = vertex
		
		text = font.render(str(i), 1, (240,100,0))

		cpp.append(((x,y),(z,t),text))

	
	#me is the arrow that tell me where i am
	me = pointer.Me(g.find_by_name("0"))
	pygame.display.set_icon(me.image)
	
	
	#display the city map
	map, map_rect = utils.load_image(file_to_open+".png")


	#message is an area that show messages
	message = Messages.Messages(screen)
	message.put_msg(str_opciones)
	while True:
		#setting the fps
		pygame.time.Clock().tick(40)

		#managing quit event
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				sys.exit()
			elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
				sys.exit()
		
		mx,my = pygame.mouse.get_pos()
		b1,b2,b3 = pygame.mouse.get_pressed()

		if b1:
			newvertex = g.find_by_pos(mx - scroll_x, my - scroll_y)
			if newvertex is not None:
				me.set_vertex(newvertex)

		#when we press d we do the Dijkstra algorithm
		if pygame.key.get_pressed()[pygame.K_d]:
			dst = message.get_msg("Selecciona el destino:")
			message.put_msg(str_opciones)
			path = Algorithm.Dijkstra(g, me.vertex.get_name(), dst)
		elif pygame.key.get_pressed()[pygame.K_c]:
			dst = message.get_msg("Selecciona el origen:")
			message.put_msg(str_opciones)
			l = loading(screen)
			l.start()
			#l.start()
			cpp_path = Algorithm.eulerian_circuit(g, g.find_by_name(dst))
			cpp_path = [ i.get_name() for i in cpp_path ]
			cpp = []
			vertex1 = g.find_by_name(cpp_path[0])
			for i,vertex in enumerate(cpp_path[1:]):
				vertex = g.find_by_name(cpp_path[i])
				x,y = vertex1.get_pos()
				z,t = vertex.get_pos()
				
				vertex1 = vertex
				
				text = font.render(str(i), 1, (240,100,0))
				cpp.append(((x,y),(z,t),text))
		elif pygame.key.get_pressed()[pygame.K_l]: #load graph
			file_to_open = message.get_msg("Cargar grafo (ejemplo: h):")
			message.put_msg(str_opciones)
			l = loading(screen)
			l.start()
			
			g = Graph.Graph(file_to_open)
		
			max = [0, 0]
			for v in g.get_vertices():
				if v.get_x() > max[0]:
					max[0] = v.get_x()
				if v.get_y() > max[1]:
					max[1] = v.get_y()
			
			screen_buffer = pygame.Surface((max[0]+50, max[1]+50))
			vertices = g.get_vertices()
		
			#calculating the vertices position and storing in a vector
			#also the names of vertices
			vertices2 = []
			for vertex in vertices:
				text = font.render(vertex.get_name(), 1, (255,255,255))
				x,y = vertex.get_pos()
				x-= text.get_width()/2
				y-= text.get_height()/2
				#[(vertex-pos, vertex-name, name-pos)]
				vertices2.append((vertex.get_pos(), text, (x,y)))
		
			#calculating the edges for drawing
			drawed = []
			weights = []
			edges = []
			for vertex in vertices:
				for adjacent in vertex.get_adjacents():
					x,y = vertex.get_pos()
					z,t = adjacent.get_pos()
					#we not include the repeated edges, a-b == b-a
					#we only paint one of these
					if member(drawed, (x,y,z,t)) or member(drawed, (z,t,y,x)):
						continue
					drawed+=[(x,y,z,t)]
					edges.append(((x,y),(z,t)))
					text = font.render(str(g.get_weight(vertex.get_name(),adjacent.get_name())), 1, (0,0,0))
					posx = (x+z) / 2
					posy = (y+t) / 2
					#[(weight, position)]
					weights.append((text,(posx,posy)))
		
			path = []
			src = "0"
			dst = str(len(g.get_vertices())- 1)
			path = Algorithm.Dijkstra(g, src, dst)
			
			g2 = copy.deepcopy(g)
			cpp_path = Algorithm.CPP(g, src, file_to_open)
			print cpp_path
			#calculating the eulerian path
			cpp = []
			vertex1 = g.find_by_name(cpp_path[0])
			for i,vertex in enumerate(cpp_path[1:]):
				vertex = g.find_by_name(cpp_path[i])
				x,y = vertex1.get_pos()
				z,t = vertex.get_pos()
				
				vertex1 = vertex
				
				text = font.render(str(i), 1, (240,100,0))
		
				cpp.append(((x,y),(z,t),text))
		
			
			#me is the arrow that tell me where i am
			me = pointer.Me(g.find_by_name("0"))
			pygame.display.set_icon(me.image)
			
			#display the city map
			try:
				map, map_rect = utils.load_image(file_to_open + ".png")
			except:
				map, map_rect = 0, 0
			#message is an area that show messages
			message = Messages.Messages(screen)
			message.put_msg(str_opciones)
		elif pygame.key.get_pressed()[pygame.K_g]: #generate graph
			n = message.get_msg("Tamanyo n:")
			m = message.get_msg("Tamanyo m:")
			file_to_open = message.get_msg("Fichero de salida out:")
			message.put_msg(str_opciones)
			l = loading(screen)
			l.start()
			graph_autogen.autogen(int(n),int(m),file_to_open)
			
			
			g = Graph.Graph(file_to_open)
		
			max = [0, 0]
			for v in g.get_vertices():
				if v.get_x() > max[0]:
					max[0] = v.get_x()
				if v.get_y() > max[1]:
					max[1] = v.get_y()
			
			screen_buffer = pygame.Surface((max[0]+50, max[1]+50))
			vertices = g.get_vertices()
		
			#calculating the vertices position and storing in a vector
			#also the names of vertices
			vertices2 = []
			for vertex in vertices:
				text = font.render(vertex.get_name(), 1, (255,255,255))
				x,y = vertex.get_pos()
				x-= text.get_width()/2
				y-= text.get_height()/2
				#[(vertex-pos, vertex-name, name-pos)]
				vertices2.append((vertex.get_pos(), text, (x,y)))
		
			#calculating the edges for drawing
			drawed = []
			weights = []
			edges = []
			for vertex in vertices:
				for adjacent in vertex.get_adjacents():
					x,y = vertex.get_pos()
					z,t = adjacent.get_pos()
					#we not include the repeated edges, a-b == b-a
					#we only paint one of these
					if member(drawed, (x,y,z,t)) or member(drawed, (z,t,y,x)):
						continue
					drawed+=[(x,y,z,t)]
					edges.append(((x,y),(z,t)))
					text = font.render(str(g.get_weight(vertex.get_name(),adjacent.get_name())), 1, (0,0,0))
					posx = (x+z) / 2
					posy = (y+t) / 2
					#[(weight, position)]
					weights.append((text,(posx,posy)))
		
			path = []
			src = "0"
			dst = str(len(g.get_vertices())- 1)
			path = Algorithm.Dijkstra(g, src, dst)
			
			g2 = copy.deepcopy(g)
			cpp_path = Algorithm.CPP(g, src, file_to_open)
			print cpp_path
			#calculating the eulerian path
			cpp = []
			vertex1 = g.find_by_name(cpp_path[0])
			for i,vertex in enumerate(cpp_path[1:]):
				vertex = g.find_by_name(cpp_path[i])
				x,y = vertex1.get_pos()
				z,t = vertex.get_pos()
				
				vertex1 = vertex
				
				text = font.render(str(i), 1, (240,100,0))
		
				cpp.append(((x,y),(z,t),text))
		
			
			#me is the arrow that tell me where i am
			me = pointer.Me(g.find_by_name("0"))
			pygame.display.set_icon(me.image)
			
			
			#display the city map
			try:
				map, map_rect = utils.load_image(file_to_open + ".png")
			except:
				map, map_rect = 0, 0
		
		
			#message is an area that show messages
			message = Messages.Messages(screen)
			message.put_msg(str_opciones)

		#left and right it's used for rotate and up to go to the next vertex
		if pygame.key.get_pressed()[pygame.K_LEFT]:
			scroll_x += 10
			#me.rotate_left()
			#pygame.time.wait(100)
		if pygame.key.get_pressed()[pygame.K_RIGHT]:
			scroll_x -= 10
			#me.rotate_right()
			#pygame.time.wait(100)
		if pygame.key.get_pressed()[pygame.K_UP]:
			scroll_y += 10
			#me.go_next()
			#pygame.time.wait(100)
		if pygame.key.get_pressed()[pygame.K_DOWN]:
			scroll_y -= 10
			
		#if we go out of the path, recalculate the dijkstra path.
		if not member(path, me.vertex):
			path = Algorithm.Dijkstra(g, me.vertex.get_name(), dst)

		#filling the screen to white
		l.running = False
		screen.fill((0,0,0))
		if map != 0:
			screen_buffer.blit(map,(0,0))
		else:
			screen_buffer.fill((0,0,0))
		
		#screen_buffer.fill((255,255,255))
		#drawing the edges in green
		for edge in edges:
			pygame.draw.line(screen_buffer, (0,255,0), edge[0],edge[1], 3)
			

		r,gr,b = 0,0,0
		op = 1
		puestos = []
		for i in cpp:
			pygame.draw.line(screen_buffer, (255,0,0), i[0],i[1], 3)
			x = ((i[0][0] + i[1][0]) / 2) + 10
			y = ((i[0][1] + i[1][1]) / 2) + 10
			while puestos.__contains__((x,y)):
				y += 14
			puestos.append((x,y))
			screen_buffer.blit(i[2], (x,y))
						
		#drawing the path in blue
		vertex = path[1]
		i = 2
		while i < len(path):
			vertex2 = path[i]
			x,y = vertex.get_pos()
			z,t = vertex2.get_pos()
			pygame.draw.line(screen_buffer, (0,0,255), (x,y),(z,t), 3)
			vertex = vertex2
			i+=1
		
		#drawing the vertices
		for vertex in vertices2:
			pygame.draw.circle(screen_buffer,(255,0,0),vertex[0],12)
			screen_buffer.blit(vertex[1], vertex[2])

		#drawing the weights
		for i in weights:
			pygame.draw.circle(screen_buffer,(255,255,255),i[1],10)
			#this is too complicated, i use i like a list with the weight information
			#and need to do operations for center the text, and this is too ugly but works
			screen_buffer.blit(i[0],(i[1][0]-i[0].get_width()/2,i[1][1]-i[0].get_height()/2))
		screen_buffer.blit(me.image, me.rect)
		screen.blit(screen_buffer, (scroll_x, scroll_y))
		message.paint()
		pygame.display.flip()
		
	

def member(visited, vertex):
	"""
	return true if the vertex is member of the visited list
	"""
	for i in visited:
		if i == vertex:
			return True
	return False
	
if __name__ == "__main__":
	main()	


